{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cf98468b-6a08-4f1c-b5e9-1e10218dab25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:02.553814Z",
     "iopub.status.busy": "2024-04-19T14:14:02.553569Z",
     "iopub.status.idle": "2024-04-19T14:14:02.994489Z",
     "shell.execute_reply": "2024-04-19T14:14:02.994209Z",
     "shell.execute_reply.started": "2024-04-19T14:14:02.553786Z"
    }
   },
   "outputs": [],
   "source": [
    "import json\n",
    "from web3 import Web3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d1c7e7f4-9fda-4dcd-a8ef-67fb8c592627",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:02.995565Z",
     "iopub.status.busy": "2024-04-19T14:14:02.995418Z",
     "iopub.status.idle": "2024-04-19T14:14:03.763214Z",
     "shell.execute_reply": "2024-04-19T14:14:03.762454Z",
     "shell.execute_reply.started": "2024-04-19T14:14:02.995555Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w3 = Web3(Web3.HTTPProvider(\"https://sepolia.infura.io/v3/824256f39eb744afb721dddb03a36600\"))\n",
    "w3.is_connected()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8de635b-13ce-40c1-835b-8ac44e0842b3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:03:44.579935Z",
     "iopub.status.busy": "2024-04-19T11:03:44.578924Z",
     "iopub.status.idle": "2024-04-19T11:03:44.585347Z",
     "shell.execute_reply": "2024-04-19T11:03:44.584488Z",
     "shell.execute_reply.started": "2024-04-19T11:03:44.579889Z"
    }
   },
   "source": [
    "# Multicall3\n",
    "\n",
    "https://github.com/mds1/multicall\n",
    "\n",
    "Deploed at `0xcA11bde05977b3631167028862bE2a173976CA11`\n",
    "\n",
    "Abi published in Sepolia / Mainnet and so on\n",
    "\n",
    "I.e. for Sepolia: https://sepolia.etherscan.io/address/0xcA11bde05977b3631167028862bE2a173976CA11#code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f094f80a-caff-426c-8234-d0fc734dd514",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:03.765194Z",
     "iopub.status.busy": "2024-04-19T14:14:03.764667Z",
     "iopub.status.idle": "2024-04-19T14:14:03.770822Z",
     "shell.execute_reply": "2024-04-19T14:14:03.770039Z",
     "shell.execute_reply.started": "2024-04-19T14:14:03.765151Z"
    }
   },
   "outputs": [],
   "source": [
    "MULTICALL3 = '0xcA11bde05977b3631167028862bE2a173976CA11'\n",
    "multicall3_abi = json.load(open(\"./abis/multicall3.abis\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "db341dfa-59f4-4637-9e86-bc30cebd07f0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:03.772737Z",
     "iopub.status.busy": "2024-04-19T14:14:03.772273Z",
     "iopub.status.idle": "2024-04-19T14:14:03.800138Z",
     "shell.execute_reply": "2024-04-19T14:14:03.799569Z",
     "shell.execute_reply.started": "2024-04-19T14:14:03.772705Z"
    }
   },
   "outputs": [],
   "source": [
    "multicall_contract = w3.eth.contract(address=MULTICALL3, abi=multicall3_abi)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ef9c0fc-c238-48bf-8c77-87df26e30662",
   "metadata": {},
   "source": [
    "**Important note:**\n",
    "\n",
    "This lib has additional helpers that implement regular RPC api calls as a contract calls to use them to wrap in multicall\n",
    "\n",
    "There are a number of other methods to return block properties, including:\n",
    "\n",
    "    getBlockHash: Returns the block hash for the given block number.\n",
    "    getBlockNumber: Returns the current block's number.\n",
    "    getCurrentBlockCoinbase: Returns the current block's coinbase.\n",
    "    getCurrentBlockDifficulty: Returns the current block's difficulty for Proof-of-Work chains or the latest RANDAO value for Proof-of-Stake chains. See EIP-4399 to learn more about this.\n",
    "    getCurrentBlockGasLimit: Returns the current block's gas limit.\n",
    "    getCurrentBlockTimestamp: Returns the current block's timestamp.\n",
    "    getEthBalance: Returns the ETH (or native token) balance of the given address.\n",
    "    getLastBlockHash: Returns the block hash of the previous block.\n",
    "    getBasefee: Returns the base fee of the given block. This will revert if the BASEFEE opcode is not supported on the given chain. See EIP-1599 to learn more about this.\n",
    "    getChainId: Returns the chain ID.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "92c85381-18d6-4e35-9051-406e80309c77",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:03.801047Z",
     "iopub.status.busy": "2024-04-19T14:14:03.800874Z",
     "iopub.status.idle": "2024-04-19T14:14:03.805923Z",
     "shell.execute_reply": "2024-04-19T14:14:03.805405Z",
     "shell.execute_reply.started": "2024-04-19T14:14:03.801030Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['abi',\n",
       " 'w3',\n",
       " 'address',\n",
       " 'aggregate',\n",
       " 'aggregate3',\n",
       " 'aggregate3Value',\n",
       " 'blockAndAggregate',\n",
       " 'getBasefee',\n",
       " 'getBlockHash',\n",
       " 'getBlockNumber',\n",
       " 'getChainId',\n",
       " 'getCurrentBlockCoinbase',\n",
       " 'getCurrentBlockDifficulty',\n",
       " 'getCurrentBlockGasLimit',\n",
       " 'getCurrentBlockTimestamp',\n",
       " 'getEthBalance',\n",
       " 'getLastBlockHash',\n",
       " 'tryAggregate',\n",
       " 'tryBlockAndAggregate']"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Get a list of SC functions (w/o python helpers)\n",
    "[i for i in multicall_contract.functions.__dir__() if not i.startswith('_')]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b37b6453-a123-48fd-a6fc-3bfc29afd7dd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:16:30.298538Z",
     "iopub.status.busy": "2024-04-19T11:16:30.298141Z",
     "iopub.status.idle": "2024-04-19T11:16:30.301878Z",
     "shell.execute_reply": "2024-04-19T11:16:30.301068Z",
     "shell.execute_reply.started": "2024-04-19T11:16:30.298512Z"
    }
   },
   "source": [
    "# Multiple Eth balance fetching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "25fa17e0-3a04-4ce5-a797-9bfe2cbe0c62",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:03.806970Z",
     "iopub.status.busy": "2024-04-19T14:14:03.806794Z",
     "iopub.status.idle": "2024-04-19T14:14:03.809932Z",
     "shell.execute_reply": "2024-04-19T14:14:03.809185Z",
     "shell.execute_reply.started": "2024-04-19T14:14:03.806952Z"
    }
   },
   "outputs": [],
   "source": [
    "MY_ADDRESS = '0x997d4c6A7cA5d524babDf1b205351f6FB623b5E7'\n",
    "# Top accounts from https://sepolia.etherscan.io/accounts\n",
    "TOP_ACCOUNT1 = '0x25c4a76E7d118705e7Ea2e9b7d8C59930d8aCD3b'\n",
    "TOP_ACCOUNT2 = '0xd7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83cedda4-f8fc-42cc-a550-3cfe7cf9e13b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:14:32.783944Z",
     "iopub.status.busy": "2024-04-19T13:14:32.783562Z",
     "iopub.status.idle": "2024-04-19T13:14:32.787665Z",
     "shell.execute_reply": "2024-04-19T13:14:32.786698Z",
     "shell.execute_reply.started": "2024-04-19T13:14:32.783919Z"
    }
   },
   "source": [
    "## Sequential request of balances via RPC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fead2a49-26fb-4927-ab6a-0f73b8b6243b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:03.813427Z",
     "iopub.status.busy": "2024-04-19T14:14:03.812954Z",
     "iopub.status.idle": "2024-04-19T14:14:05.465823Z",
     "shell.execute_reply": "2024-04-19T14:14:05.464367Z",
     "shell.execute_reply.started": "2024-04-19T14:14:03.813408Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('6.031617160292639647',\n",
       " '100000480.071687981671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.071687981671356374',\n",
       " '100000000.00107')"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Sequential get accounts balances\n",
    "(\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "34b45392-b33a-45c1-8c08-351c5a515006",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:05.467233Z",
     "iopub.status.busy": "2024-04-19T14:14:05.466957Z",
     "iopub.status.idle": "2024-04-19T14:14:16.565505Z",
     "shell.execute_reply": "2024-04-19T14:14:16.564246Z",
     "shell.execute_reply.started": "2024-04-19T14:14:05.467211Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.14 s ± 187 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "27fa154a-f5ab-4873-a7bd-f4e5928b61de",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:16:25.408974Z",
     "iopub.status.busy": "2024-04-19T13:16:25.408614Z",
     "iopub.status.idle": "2024-04-19T13:16:25.414336Z",
     "shell.execute_reply": "2024-04-19T13:16:25.413382Z",
     "shell.execute_reply.started": "2024-04-19T13:16:25.408949Z"
    }
   },
   "source": [
    "**Note here**\n",
    "\n",
    "Above operation takes ~1.08s/1.03s/1.04s on my machine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "0ecf6370-899c-4044-92ef-56ca9d398f9c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:16.567360Z",
     "iopub.status.busy": "2024-04-19T14:14:16.567110Z",
     "iopub.status.idle": "2024-04-19T14:14:22.489247Z",
     "shell.execute_reply": "2024-04-19T14:14:22.487937Z",
     "shell.execute_reply.started": "2024-04-19T14:14:16.567338Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('6.031617160292639647',\n",
       " '100000480.075121037671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.075121037671356374',\n",
       " '100000000.00107')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Sequential get account balance via Multicall3\n",
    "(\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2cc73765-86d3-405d-b21e-39736a194f30",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:22.491366Z",
     "iopub.status.busy": "2024-04-19T14:14:22.490967Z",
     "iopub.status.idle": "2024-04-19T14:14:43.425024Z",
     "shell.execute_reply": "2024-04-19T14:14:43.423818Z",
     "shell.execute_reply.started": "2024-04-19T14:14:22.491335Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.36 s ± 381 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "(\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(MY_ADDRESS).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT1).call(),unit='ether')),\n",
    "    str(w3.from_wei(multicall_contract.functions.getEthBalance(TOP_ACCOUNT2).call(),unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24da990e-b8a8-4351-856c-2cbb752cc43a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T13:17:12.013775Z",
     "iopub.status.busy": "2024-04-19T13:17:12.013427Z",
     "iopub.status.idle": "2024-04-19T13:17:12.016928Z",
     "shell.execute_reply": "2024-04-19T13:17:12.016173Z",
     "shell.execute_reply.started": "2024-04-19T13:17:12.013751Z"
    }
   },
   "source": [
    "## Parallel getBalance via Multicall3 aggregate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "75fdf259-9369-4958-979d-3c87ccbc5306",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:43.429116Z",
     "iopub.status.busy": "2024-04-19T14:14:43.428501Z",
     "iopub.status.idle": "2024-04-19T14:14:43.443270Z",
     "shell.execute_reply": "2024-04-19T14:14:43.441688Z",
     "shell.execute_reply.started": "2024-04-19T14:14:43.429073Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7',\n",
       " '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b',\n",
       " '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# prepare function call encode data\n",
    "get_balance_of_MY_ACCOUNT_call = multicall_contract.functions.getEthBalance(MY_ADDRESS)._encode_transaction_data()\n",
    "get_balance_of_TOP_ACCOUNT1_call = multicall_contract.functions.getEthBalance(TOP_ACCOUNT1)._encode_transaction_data()\n",
    "get_balance_of_TOP_ACCOUNT2_call = multicall_contract.functions.getEthBalance(TOP_ACCOUNT2)._encode_transaction_data()\n",
    "get_balance_of_MY_ACCOUNT_call, get_balance_of_TOP_ACCOUNT1_call, get_balance_of_TOP_ACCOUNT2_call"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "34c83d21-f7fa-4987-b213-172716f56b25",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:43.444943Z",
     "iopub.status.busy": "2024-04-19T14:14:43.444611Z",
     "iopub.status.idle": "2024-04-19T14:14:43.462938Z",
     "shell.execute_reply": "2024-04-19T14:14:43.462312Z",
     "shell.execute_reply.started": "2024-04-19T14:14:43.444911Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Function aggregate((address,bytes)[]) bound to ([['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e7'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b'], ['0xcA11bde05977b3631167028862bE2a173976CA11', '0x4d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e']],)>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "'0x252dba420000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e700000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000997d4c6a7ca5d524babdf1b205351f6fb623b5e700000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc00000000000000000000000025c4a76e7d118705e7ea2e9b7d8c59930d8acd3b00000000000000000000000000000000000000000000000000000000000000000000000000000000ca11bde05977b3631167028862be2a173976ca11000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000244d2301cc000000000000000000000000d7d76c58b3a519e9fa6cc4d22dc017259bc49f1e00000000000000000000000000000000000000000000000000000000'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# prepare function call of aggregate with a list encoded function call data \n",
    "multicall_call = multicall_contract.functions.aggregate([\n",
    "    [MULTICALL3, get_balance_of_MY_ACCOUNT_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT1_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT2_call],\n",
    "    [MULTICALL3, get_balance_of_MY_ACCOUNT_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT1_call],\n",
    "    [MULTICALL3, get_balance_of_TOP_ACCOUNT2_call],\n",
    "])\n",
    "display(multicall_call)\n",
    "multicall_call._encode_transaction_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "18b85795-130c-4296-b1c4-3eca7be01fff",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:43.464764Z",
     "iopub.status.busy": "2024-04-19T14:14:43.464240Z",
     "iopub.status.idle": "2024-04-19T14:14:43.814670Z",
     "shell.execute_reply": "2024-04-19T14:14:43.813694Z",
     "shell.execute_reply.started": "2024-04-19T14:14:43.464742Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5732171,\n",
       " [b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe3<_\\xd7\\x99\\xea_\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00S\\xb4\\x9b\\xd9\\xb4d\\xa3\\x9f',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xec\\xe3<_\\xd7\\x99\\xea_\\xd6',\n",
       "  b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00R\\xb7\\xd2\\xdc\\xcb\\xd9\\xfb\\xad\\xe8\\xe0\\x00']]"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Parallel call to multiple ETH balances\n",
    "result = multicall_call.call()\n",
    "result\n",
    "# First element it is block number\n",
    "# Second element it is an array of results\n",
    "# Results are array of bytes and you need to know how to interpret this values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "7733322e-e440-4597-aa87-e3e5b920dfd3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:43.816406Z",
     "iopub.status.busy": "2024-04-19T14:14:43.816132Z",
     "iopub.status.idle": "2024-04-19T14:14:46.609672Z",
     "shell.execute_reply": "2024-04-19T14:14:46.608480Z",
     "shell.execute_reply.started": "2024-04-19T14:14:43.816382Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "349 ms ± 20.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%%timeit\n",
    "result = multicall_call.call()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4af80607-adc6-49a9-860f-ee93866ecf83",
   "metadata": {},
   "source": [
    "**(!!!) Note here**\n",
    "\n",
    "Above call executed in ~357/350/349ms on my machine, that is way faster sequential request of balances\n",
    "\n",
    "Because aggregate is a single request to RPC api not a 6 different requests"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a05ab52-994a-401b-a246-d7e170fb60c4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T11:43:21.628559Z",
     "iopub.status.busy": "2024-04-19T11:43:21.628182Z",
     "iopub.status.idle": "2024-04-19T11:43:21.634279Z",
     "shell.execute_reply": "2024-04-19T11:43:21.631814Z",
     "shell.execute_reply.started": "2024-04-19T11:43:21.628534Z"
    }
   },
   "source": [
    "# Interprets a results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3412d632-1d2f-4bcd-aacd-fa827ecb4740",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:46.612112Z",
     "iopub.status.busy": "2024-04-19T14:14:46.611628Z",
     "iopub.status.idle": "2024-04-19T14:14:46.617028Z",
     "shell.execute_reply": "2024-04-19T14:14:46.615716Z",
     "shell.execute_reply.started": "2024-04-19T14:14:46.612087Z"
    }
   },
   "outputs": [],
   "source": [
    "from eth_abi import decode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "8007dc61-94c9-4bbe-bbfc-0126eee999bf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:16:02.251374Z",
     "iopub.status.busy": "2024-04-19T14:16:02.251026Z",
     "iopub.status.idle": "2024-04-19T14:16:02.256926Z",
     "shell.execute_reply": "2024-04-19T14:16:02.256001Z",
     "shell.execute_reply.started": "2024-04-19T14:16:02.251350Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'inputs': [{'internalType': 'address', 'name': 'addr', 'type': 'address'}],\n",
       " 'name': 'getEthBalance',\n",
       " 'outputs': [{'internalType': 'uint256',\n",
       "   'name': 'balance',\n",
       "   'type': 'uint256'}],\n",
       " 'stateMutability': 'view',\n",
       " 'type': 'function'}"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# you need to know abi of calls\n",
    "multicall_contract.functions.getEthBalance(MY_ADDRESS).abi\n",
    "# so outputs are only one param with type = uint256"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "25c2c62c-98ad-4b9a-8e87-5be196c1fe2f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:46.627869Z",
     "iopub.status.busy": "2024-04-19T14:14:46.627554Z",
     "iopub.status.idle": "2024-04-19T14:14:46.633622Z",
     "shell.execute_reply": "2024-04-19T14:14:46.632622Z",
     "shell.execute_reply.started": "2024-04-19T14:14:46.627841Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(6031617160292639647,)\n",
      "(100000480080433857671356374,)\n",
      "(100000000001070000000000000,)\n",
      "(6031617160292639647,)\n",
      "(100000480080433857671356374,)\n",
      "(100000000001070000000000000,)\n"
     ]
    }
   ],
   "source": [
    "for i in result[1]:\n",
    "    print(decode(types=['uint256'],data=i))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a568a589-438e-4eb0-8dc1-3fe478b4fab2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:46.634849Z",
     "iopub.status.busy": "2024-04-19T14:14:46.634611Z",
     "iopub.status.idle": "2024-04-19T14:14:46.640810Z",
     "shell.execute_reply": "2024-04-19T14:14:46.640102Z",
     "shell.execute_reply.started": "2024-04-19T14:14:46.634826Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('6.031617160292639647',\n",
       " '100000480.080433857671356374',\n",
       " '100000000.00107',\n",
       " '6.031617160292639647',\n",
       " '100000480.080433857671356374',\n",
       " '100000000.00107')"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check = tuple([str(w3.from_wei(decode(types=['uint256'],data=i)[0], unit='ether'))\n",
    " for i in result[1]])\n",
    "check"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "34d1073c-1e10-442d-8941-97a03f9e2259",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-04-19T14:14:48.770076Z",
     "iopub.status.busy": "2024-04-19T14:14:48.769589Z",
     "iopub.status.idle": "2024-04-19T14:14:50.131870Z",
     "shell.execute_reply": "2024-04-19T14:14:50.130657Z",
     "shell.execute_reply.started": "2024-04-19T14:14:48.769989Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check = tuple([str(w3.from_wei(decode(types=['uint256'],data=i)[0], unit='ether'))\n",
    " for i in multicall_call.call()[1]])\n",
    "check == (\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(MY_ADDRESS), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT1), unit='ether')),\n",
    "    str(w3.from_wei(w3.eth.get_balance(TOP_ACCOUNT2), unit='ether')),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "834c0eb8-1576-4d99-ad3c-bf29702f4bf6",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
